home *** CD-ROM | disk | FTP | other *** search
- ; +-------------------+
- ; | |
- ; | 68K-Macros |
- ; | |
- ; +-------------------+
- ;
- ; 68K-Macros - macros to improve on the 68000's instruction mnemonics.
- ;
- ; %W%\t%G% - SCCS Info
- ;
- ; These macros are mostly intended to augment the 68000 instruction set.
- ; Some, like "compare", simply reverse the arguments to make it easier to
- ; understand. Others facilitate creation of structured code.
- ;
- ; Revision History:
- ;
- ; 8806?? RPM Start HyperTape II project. All revision history for HyperTape
- ; II is stored in the SCCS delta comment lines.
-
- ; Macros to make the "cmp" instruction logical by un-reversing its arguments.
- ;
- macro compare arg1,arg2 =
- cmp.w {arg2},{arg1}
- |
-
- macro compare_l arg1,arg2 =
- cmp.l {arg2},{arg1}
- |
-
- macro compare_b arg1,arg2 =
- cmp.b {arg2},{arg1}
- |
-
- ; Lsl and Lsr by 16 bits, a common operation.
- ;
- macro lsl_16 arg1 =
- swap {arg1}
- clr {arg1}
- |
-
- macro lsr_16 arg1 =
- clr {arg1}
- swap {arg1}
- |
-
- ; Save/restore all registers, another common operation
- ;
- macro SAVE_ALL =
- movem.l d0-d7/a0-a4,-(sp)
- |
-
- macro RESTORE_ALL =
- movem.l (sp)+,d0-d7/a0-a4
- |
-
-
- macro _DebugStr =
- dc.w $abff
- |
-
- ; Apparently, with MDS 2.0 the construct "pea 'MyText'" does not automatically
- ; declare the text and push the pc-relative address the way it used to in older
- ; versions. Therefore, this macro was written. It declares the text, jumps
- ; around the declaration, pushes the address, and invokes the trap.
- ;
- IF DBUG
- macro DEBUGSTR text =
- bra.s @9
- @8:
- dc.b 16,{text}
- dc.b 32, 32, 32, 32, 32, 32, 32, 32
- dc.b 32, 32, 32, 32, 32, 32, 32, 32
- .align 2
- @9:
- pea @8
- _DebugStr
- |
- ENDIF
-
- ; If you have a "DEBUG.STR" macro, just delete the "D" to temporarily "comment
- ; it out". Of course, once debugging is complete the debugging macros should
- ; all be removed from the source.
- ;
- macro EBUGSTR text =
- ; does nothing
- |
-
- ; Macros for calling the debugLog2 subroutine.
- ;
- IF DBUG
- macro DEBUGLOG value =
- move {value},-(sp)
- bsr debugLog2
- |
- ENDIF
-
- macro EBUGLOG value =
- ; does nothing
- |
-
- ; This is used to insert human-readable labels in code (to make up for the
- ; fact that in assembler you can't create labels which TMON will notice).
- ;
- IF DBUG
- macro LABEL text =
- dc.b '<<'
- dc.b {text}
- dc.b '>>'
- .align 2
- |
- ELSE
- macro LABEL text =
- ; nothing
- |
- ENDIF
-
- ; ===================== New stack-based subroutine macros =====================
- ;
- ; These macros make it easier to implement stack-based subroutines and
- ; functions, using Apple's standard stack-based calling sequence. They save
- ; the programmer from having to think about how the frame pointer is saved, set
- ; up, and restored, and from having to figure out the total length of the local
- ; variable space (for use in the LINK instruction.) Locals and parameters are
- ; referred to as locl_name(A6) and parm_name(A6), respectively. The return
- ; value (if any) is referred to by (A6).
- ; These macros use A6 as the parameter frame pointer, and restore its value
- ; when the subroutine ends.
- ;
- ; When a subroutine is called by the standard Mac Pascal calling sequence,
- ; the stack looks something like this:
- ;
- ; SP
- ; |
- ; ----+-----------+-----+-----------+-----------+---
- ; Stack grows| return |word | long | return | higher
- ;<-- this way| address |param| param | value | memory
- ; ----+-----------+-----+-----------+-----------+---
- ;
- ; At the beginning of your subroutine, use the STACK_DECLARE macro, followed by
- ; one or more BYTE_PARAM, WORD_PARAM, and LONG_PARAM macros to declare the
- ; parameters of the subroutine. These macros set the assembler variables for
- ; the offsets to each parameter and the total length of the parameter space.
- ; Declare the parameters in Pascal ordering, i.e. the same order that
- ; they're pushed onto the stack when the subroutine is called.
- ;
-
- macro STACK_DECLARE =
- last_param set 0
- |
-
-
- macro BYTE_PARAM name =
- last_param set last_param - 2
- parm_{name} set last_param
- |
-
- macro WORD_PARAM name =
- last_param set last_param - 2
- parm_{name} set last_param
- |
-
- macro LONG_PARAM name =
- last_param set last_param - 4
- parm_{name} set last_param
- |
-
- ; After declaring the parameters, use the STACK_BEGIN macro. This macro
- ; saves A6 on the stack, then makes A6 point to the first byte after the last
- ; byte in the parameter space. In other words, A6 points at the return value
- ; (if any). After STACK_BEGIN, the stack looks like this:
- ;
- ; SP last_param(A6) A6
- ; | | |
- ; ----+-----------+-----------+-----+-----------+-----------+---
- ; Stack grows| old | return |word | long | return | higher
- ;<-- this way| A6 | address |param| param | value | memory
- ; ----+-----------+-----------+-----+-----------+-----------+---
- ;
- ; Please note that this is quite different from the LINK instruction, which
- ; is normally used to start a stack-based subroutine. If we used LINK, the
- ; implementation of these macros would be somewhat more complex (because LINK
- ; requires knowledge of the size of the local variable space.)
- ;
- macro STACK_BEGIN =
- move.l a6,-(sp)
- lea 8-last_param(sp),a6
- last_local set last_param - 8
- |
-
- ; Next, use the macros BYTE_LOCAL, WORD_LOCAL, LONG_LOCAL, and ARRAY_LOCAL
- ; to declare the local variables. These macros generate code to move the stack
- ; pointer down by the appropriate amount for each local variable. After the
- ; locals are declared, the stack will look something like this:
- ;
- ; SP A6
- ; | |
- ; ----+-----+-----+-----------+-----------+-----+-----------+-----------+---
- ; Stack grows|byte |word | old | return |word | long | return | higher
- ;<-- this way|local|local| A6 | address |param| param | value | memory
- ; ----+-----+-----+-----------+-----------+-----+-----------+-----------+---
- ;
- macro LONG_LOCAL name =
- last_local set last_local - 4
- locl_{name} set last_local
- subq.l #4,sp
- |
-
- macro WORD_LOCAL name =
- last_local set last_local - 2
- locl_{name} set last_local
- subq.l #2,sp
- |
-
- macro BYTE_LOCAL name =
- last_local set last_local - 2
- locl_{name} set last_local
- subq.l #2,sp
- |
-
- ; NOTE: When declaring an array local, the number of bytes specified MUST be
- ; an even number. If it isn't, the Mac will reboot (really!) as soon as the
- ; subroutine tries to use the stack or call another subroutine. (Trying to
- ; push or pop something on the stack when the SP is odd causes a "double bus
- ; fault", which causes the system to reboot.)
- ;
- macro ARRAY_LOCAL name,size =
- last_local set last_local - {size}
- locl_{name} set last_local
- lea -{size}(sp),sp
- |
-
- ; After the parameters and locals are declared, start the actual code of the
- ; subroutine. Refer to a local or parameter "foo" by "locl_foo(A6)" or
- ; "parm_foo(A6)" as appropriate. Refer to the return value as "(A6)".
- ;
-
- ; At the end of the subroutine, use the STACK_END macro in place of an RTS
- ; instruction. Note that the subroutine might have left some extra garbage on
- ; the stack. Therefore, the stack will look something like this:
- ;
- ; SP last_param-8(A6) last_param(A6) A6
- ; | | | |
- ; ----+-----------+-----+-----+-----------+-----------+-----+-----------+-----------+---
- ; Stack grows| extra |byte |word | old | return |word | long | return | higher
- ;<-- this way| garbage |local|local| A6 | address |param| param | value | memory
- ; ----+-----------+-----+-----+-----------+-----------+-----+-----------+-----------+---
- ;
- ; STACK_END works in five steps: First, it discards the garbage and the local
- ; variables by setting the SP to the location of the old A6. Second, it pops
- ; the old A6 off the stack to restore A6. Third, it copies the return address
- ; onto the top four bytes of the parameter space. Then, it points the SP at
- ; this address. Finally, it does an RTS, leaving the stack empty except for
- ; the return value. (The reason RTS is used instead of JMP (A0) or something
- ; like that is to preserve A0.)
- ; NOTE: It is done this way to make sure the macro works even if the
- ; subroutine has no parameters.
- ;
- macro STACK_END =
- lea last_param-8(a6),sp
- move.l (sp)+,a6
- move.l (sp),-last_param(sp)
- lea -last_param(sp),sp
- rts
- |
-
- ; ==================== Example ==================
- ;
- ; In this example, we want to write an assembly-language subroutine which
- ; is called in the same way as a Pascal routine with the following calling
- ; sequence:
- ;
- ; Function MyFilter (theDialog: DialogPtr; VAR theEvent: EventRecord;
- ; VAR itemHit: INTEGER) : BOOLEAN;
- ;
- ; We can write such a subroutine in the following way:
- ;
- ; _MyFilter
- ; STACK_DECLARE
- ; LONG_PARAM dialog_ptr
- ; LONG_PARAM event_rec_ptr
- ; LONG_PARAM item_hit_ptr
- ;
- ; STACK_BEGIN
- ; WORD_LOCAL foo
- ; BYTE_LOCAL bar
- ;
- ; SAVE_ALL ; Save registers
- ;
- ; move.w #0, locl_bar(a6) ; initialize locals
- ; move.w #$ffff, locl_foo(a6)
- ;
- ; move.l parm_event_rec_ptr(a6), a0 ; Get pointer to Event Record
- ; move.w evtNum(a0), d0 ; Get event code
- ;
- ; ; (etc....)
- ;
- ; move.w d1, (a6) ; Set value to return
- ;
- ; RESTORE_ALL ; restore registers
- ;
- ; STACK_END ; Return
- ;
-
- ; end of 68K-Macros
-
-